/*******************************************************************************
*  file    : transform_dif.cpp
*  created : 23.06.2014
*  author  : Slyshyk Oleksiy (alexSlyshyk@gmail.com)
*******************************************************************************/

#include "transform_int_dif.hpp"
#include <QDebug>
#include <algorithm>
#include <QVariantMap>

#include <utils.hpp>
#include <exception>


TransformIntDif::TransformIntDif(QObject *parent) :
    QObject(parent)
{

}

QString TransformIntDif::name() const
{
    return QStringLiteral("Dif_Int");
}

NamedIntData *TransformIntDif::transform(const NamedIntData *data, const QVariant &params)
{
    QScopedPointer<plugin_utils::TransformParamsPrivate> data_;
    data_.reset(new plugin_utils::TransformParamsPrivate );
    data_->setParams(params);

    auto sample = plugin_utils::read_simple_from_file<int32_t>(data_->patternFileName());
    NamedIntData* res = new NamedIntData;
    res->name = data->name + "_dif_int";
    res->pantry["id"] = params.toMap()["id"];

    if(data_->freqCoef() == 0)
        data_->setSampleRate(1.0);

    int data_sz = data->data.size() * data_->freqCoef();

    res->sampleRate = data->sampleRate * data_->freqCoef();

    res->data.resize(data_sz);

    transform(sample, data, res, data_.data());
    // Нормализация
    plugin_utils::normalize(res->data, static_cast<int32_t>(data_->normalization()));

    return res;
}

QStringList TransformIntDif::patternList() const
{
    return plugin_utils::fileList(QStringLiteral("pattern*.dat"));
}

void TransformIntDif::transform(const std::vector<int32_t> &sample, const NamedIntData *data,
                               NamedIntData *res, plugin_utils::TransformParamsPrivate* data_)
{
    int32_t start_time = 0;
    int32_t dt = 1 ;
    int32_t dt_data = 1 * data_->freqCoef();

    int32_t  d,s,fx_i;
    int32_t sample_steps = sample.size() * data_->freqCoef();
    const auto &dat = data->data;

    uint32_t iter_count = 0;
    int32_t  min_ansver = std::numeric_limits<int>::max() - 1;
    int32_t  min_ansver_idx = 0;

    if(data_->prevTime() > 0.000001)
        {
            data_->setZoneBegin(data_->prevTime() - 0.0000090);
            data_->setZoneEnd  (data_->prevTime() + 0.0000090);
        }

    int32_t idx_start = data_->zoneBegin() * res->sampleRate;
    int32_t idx_end   = data_->zoneEnd()   * res->sampleRate;

    if(static_cast<uint32_t>(idx_end) > res->data.size())
        idx_end = res->data.size();

    for(int32_t idx_data = idx_start; idx_data < idx_end ; ++idx_data)
        {
            fx_i = 0;

            for(int32_t idx_sample = 0; idx_sample < sample_steps; ++idx_sample)
                {
                    d = plugin_utils::get_func_value_linear(dat   ,start_time            ,dt_data,(idx_data+idx_sample)*dt);
                    s = plugin_utils::get_func_value_linear(sample,start_time+idx_data*dt,dt_data,(idx_data+idx_sample)*dt);
                    d -= data_->fxOffset();
                    s -= data_->fxOffset();
                    fx_i += std::abs(d - s) ;
                    iter_count++ ;
                    if(fx_i > min_ansver)
                        {
                            fx_i = 1000000;
                            break;
                        }
                }
            if(fx_i < min_ansver)
                {
                    min_ansver = fx_i;
                    min_ansver_idx = idx_data;
                }



            res->data[idx_data] = fx_i;
            if(idx_data > 2)
                {
                    int32_t dif_1 = res->data[idx_data-1] - res->data[idx_data-2];
                    int32_t dif_2 = res->data[idx_data-0] - res->data[idx_data-1];
                    if(dif_1 < 0 && dif_2 > 0 )
                        {
                            for(int32_t i = 0; i < 10*data_->freqCoef() ; ++i)
                                {
                                    idx_data+=1;
                                    res->data[idx_data] = 3000000;
                                }
                        }
                }
         }



    auto st = std::adjacent_find(res->data.begin(),res->data.end(),
                                 [](const uint32_t& d1,const uint32_t& d2)->bool
                                 {return ((d1 == 0) && (d2 > 0));});
    if(st != res->data.end())
        st++;
    auto end = std::adjacent_find(st,res->data.end(),
                                 [](const uint32_t& d1,const uint32_t& d2)->bool
                                 {return ((d1 == 0) && (d2 == 0));});

    auto max = std::max_element(st, end, std::less<uint32_t>());
    auto min = std::min_element(st, end, std::less<uint32_t>());

    data_->setMinIdx( std::distance(res->data.begin(),min) );
    data_->setMaxIdx( std::distance(res->data.begin(),max) );
    res->pantry["max_idx"]    = data_->maxIdx();
    res->pantry["min_idx"]    = data_->minIdx();
    res->pantry["ansver_idx"] = data_->minIdx();
    res->pantry["iter_count"] = iter_count ;

    qDebug() << "Iter count Heuristic " << iter_count;
}


